
package com.x52im.rbchat.logic.sns_friend;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.eva.android.widget.DataLoadableActivity;
import com.eva.android.widget.AListAdapter2;
import com.eva.android.widget.alert.AlertDialog;
import com.eva.epc.common.util.CommonUtils;
import com.eva.framework.dto.DataFromServer;
import com.x52im.rbchat.MyApplication;
import com.x52im.rbchat.R;
import com.x52im.rbchat.cache.ImageCacheLoader;
import com.x52im.rainbowchat.http.logic.dto.RosterElementEntity;
import com.x52im.rbchat.logic.alarm.AlarmType;
import com.x52im.rbchat.logic.alarm.AlarmsActivity;
import com.x52im.rbchat.logic.sns_friend.model.FriendsReqItemValue;
import com.x52im.rbchat.network.http.HttpRestHelper;
import com.x52im.rbchat.network.http.async.QueryOfflineFriendsReqAsync;
import com.x52im.rbchat.utils.IntentFactory;
import com.x52im.rbchat.utils.PreferencesToolkits;

import java.util.ArrayList;

/**
 * “验证通知”列表Activity实现类。
 * <p>
 * 截止20171226日，本界面中暂时只处理好友请求这样的通知（列出的是服务端
 * 记录的未处理的加好友请求），日后实现群聊等（比如群聊中的加群请求），相
 * 应地扩展本类中的“验证通知”类型即可.
 * <p>
 * 本类的实现完全参考自{@link AlarmsActivity}，没有重用{@link AlarmsActivity}的目的
 * 是给本类留下自定义的空间哦.
 * 
 * @author Jack Jiang(http://www.52im.net/space-uid-1.html)
 * @since 2.5
 * @see AlarmsActivity
 */
public class FriendsReqListActivity extends DataLoadableActivity
{
	// 请求码：前往加好友请求的处理页面
	public final static int REQUEST_CODE_FOR_PROCESS = 1;
	
	private final static String TAG = FriendsReqListActivity.class.getSimpleName();
	
	/** 明细列表 */
	private ListView listView;
	/** 明细列表Adapter */
	private FriendsReqListAdapter listAdapter;
	/** 布局：没有消息时的提示 */
	private LinearLayout llNoAlarms = null;
	
	/**
	 * 本方法由父类的onCreate()调用，子类可在此方法中实现自已的UI显示逻辑。
	 */
	@Override
	protected void initViews(Bundle savedInstanceState)
	{
		//设定自定义标题栏（设定此值即意味着开启自定义标题栏的使用，必须要在setContentView前设定）
		customeTitleBarResId = R.id.main_verification_reminders_list_titleBar;
		//养成良好习惯：首先设置主layout，确保后绪的操作中使用到的组件都可以被find到
		setContentView(R.layout.sns_friends_req_list_activity);
		
		//列表无数据时的UI提示信息组件
		llNoAlarms = (LinearLayout)findViewById(R.id.main_verification_reminders_list_noAlarmsLL);

		//列表及列表的adapter
		listView = (ListView) findViewById(R.id.main_verification_reminders_list_listView);
		listAdapter = new FriendsReqListAdapter(this);
		listView.setAdapter(listAdapter);
		
//		registerForContextMenu(listView);
		this.setTitle(R.string.verification_reminders_title);
	}
	
	/**
	 * 本方法由父类的onCreate()调用，子类可在此方法中为各UI功能组件增加事件临听。
	 */
	@Override
	protected void initListeners()
	{
		listView.setOnItemClickListener((parent, view, position, id) -> {
			FriendsReqItemValue amd = listAdapter.getItem(position);
			if (amd.getUserInfo() != null) {
				// 将选中的好友请求传到新activity中
				startActivityForResult(IntentFactory.createFriendReqProcessIntent(FriendsReqListActivity.this, amd.getUserInfo()), REQUEST_CODE_FOR_PROCESS);
			} else {
				// 显示提示信息
				new AlertDialog.Builder(FriendsReqListActivity.this)
						.setCancelable(false)
						.setTitle($$(R.string.general_prompt))
						.setMessage($$(R.string.verification_reminders_goto_friendinfo_invalid_data))
						.setPositiveButton($$(R.string.general_got_it), null)
						.show();
			}
		});

		// 没有好友请求时，点击进入邀请好友界面（发邀请邮件）
		llNoAlarms.setOnClickListener(view -> startActivity(IntentFactory.createInviteFriendIntent(FriendsReqListActivity.this)));
	}
	
	/**
	 * 准备好要显示的数据集合.
	 */
	@Override 
	protected DataFromServer queryData(String... params)
	{
		return QueryOfflineFriendsReqAsync.queryOfflineBeAddFriendsReq(this);
	}
	
	/**
	 * 把数据刷新到ui上.
	 */
	@Override 
	protected void refreshToView(Object dataToView)
	{
		if(dataToView != null)
		{
			ArrayList<RosterElementEntity> srcFriendsReq = HttpRestHelper.parseGetOfflineAddFriendsReqFromServer((String)dataToView);
			
			// 将好友的请求数据解析后用于列表显示
			ArrayList<FriendsReqItemValue> datasToList = new ArrayList<>();
			if(srcFriendsReq.size() > 0)
			{
				// 上次点击进入好友请求列表时，该列表中最新一条请求的时间戳
				long lastLatestReqTimestamp = PreferencesToolkits.getHasReadLatestFriendReqTimestamp(MyApplication.getInstance2());
				// 组织好友请求列表数据
				for(RosterElementEntity ree : srcFriendsReq)
				{
					// 请求时间（自v4.3以后，ree.getEx10()存放的是时间戳，而非人类可读的时间字串，见http接口手册中"【接口1008-4-7】"）
					long date = CommonUtils.getLongValue(ree.getEx10());
					// 是否是"未读"的请求
					boolean unread = true;

					// 请求内容（根据约定，ree.getEx1()存放的是好友请求内容，见http接口手册中"【接口1008-4-7】"）
					String content = ree.getEx1();
					if(CommonUtils.isStringEmpty(content, true))
						content = $$(R.string.verification_reminders_list_item_content);

					// 当请求时间戳大于上次已读的，就表示这是新的"未读"，作一个标记（以备ui上显示此条时给出特殊标记）
					// 关于"已读"、"未读"的实现和判断逻辑，请见：QueryOfflineFriendsReqAsync.calculateUnreadFriendReqCount(..)方法的注释
					if (date > lastLatestReqTimestamp) {
						unread = true;
					}
					else{
						unread = false;
					}

					datasToList.add(new FriendsReqItemValue(content, date, unread, ree));
				}
				
				//** 以下代码用于更新“首页”上的未处理添加好友Alarm的未读数据（为了防止某些情况下手机端并未能同步
	            //** 实际的服务端未处时好友请求数，正好借本界面中加载最新好友请求数据的机会刷新一下，既能省一次单独
	            //** 的网络调用，又能把“首页”的未处理好友请求Alarm的item上未读数同步，一举两得）
				// 最新一条好友请求的数据（服务端返回的加好友请求通知是按发起时间DESC逆序排列的，索引0就是最新的请求，详见HTTP接口说明）
				RosterElementEntity latestRee = srcFriendsReq.get(0);

				// 自v4.3以后，本字段存放的是时间戳，而非人类可读的时间字串
				long reqTime = CommonUtils.getLongValue(latestRee.getEx10());

				int unreadTotlaCount = 0;//srcFriendsReq.size()
				// 未读总数添加到首页通知的数据模型中（进了本界面就表示全部已读，未读总数直接设0）
				MyApplication.getInstance(this).getIMClientManager().getAlarmsProvider()
					.addAddFriendReqMergeAlarm(latestRee.getUser_uid(), latestRee.getNickname(), reqTime, unreadTotlaCount, true, false);// 注意：merge参数是NO哦
				// 设置好友请求全局缓存中的总未读数（进了本界面就表示全部已读，未读总数直接设0）
				MyApplication.getInstance(this).getIMClientManager().getFriendsReqProvider().setUnreadCount(unreadTotlaCount,true);
				// 同时把最近一次已读的最新一条请求时间戳保存起来，已备下次在未打开本界面的情况下计算未读总数
				PreferencesToolkits.setHasReadLatestFriendReqTimestamp(this, reqTime);
			}
			// 服务端返回的数据显示未处理的好友请求为0
            else
            {
                // 则即时重置“首页”的未处理好友请求Alarm的item上未读数（为0）
            	MyApplication.getInstance(this).getIMClientManager().getAlarmsProvider().resetAddFriendReqAlarmFlagNum();
            	// 重置好友请求全局缓存中的总未读数
				MyApplication.getInstance(this).getIMClientManager().getFriendsReqProvider().clearUnreadCount(true);
            }
			
			// 用新数据刷新列表显示
			listAdapter.setListData(datasToList);
		}
		return;
	}
	
//	// 去掉EVA通用类中的默认“返回”菜单项
//	public boolean onCreateOptionsMenu(Menu menu)
//	{
//		return false;
//	}
	
	/**
	 * 清除界面列表中的指定item.
	 * 
	 * @param uid
	 */
	private void clearAddFriendReqItems(String uid)
	{
		// 删除一个列表内容时应从尾往前删除哦（否则会出现经典逻辑bug哦）
		for (int i = listAdapter.getListData().size() - 1; i >= 0; i--) {
			FriendsReqItemValue amd = listAdapter.getListData().get(i);
			if (amd.getUserInfo() != null && amd.getUserInfo().getUser_uid().equals(uid)) {
				// 先从列表中删除匹配到的该条item
				listAdapter.removeItem(i);

				// 首页“消息”界面中的“验证消息”未读数-1（此界面列表中的1个item其实就对应于首页消息里的未读数1）
				MyApplication.getInstance(this).getIMClientManager().getAlarmsProvider().accumulateFlagNum(AlarmType.addFriendRequest, null, -1);
				// 设置好友请求全局缓存中的总未读数
				MyApplication.getInstance2().getIMClientManager().getFriendsReqProvider().addUnreadCount(-1, true);
			}
		}
	}
	
	/**
	 * 处理回调.
	 * {@inheritDoc}
	 */
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		// 处理完好友请求后的回调
		if (requestCode == REQUEST_CODE_FOR_PROCESS) {// 好友请求处理完成了
			if (resultCode == Activity.RESULT_OK) {
				String prodessedUid = (String) data.getStringExtra(FriendReqProcessActivity.RESULT_EXTRA_IDENT_PROCESSED_UID);
				// 请除界面列表中该好友的请求信息
				clearAddFriendReqItems(prodessedUid);
			}
		}
	}
	
	
	//---------------------------------------------------------------------------------------- inner class
	/**
	 * 自定义明细列表的adapter类实现.
	 */
	private class FriendsReqListAdapter extends AListAdapter2<FriendsReqItemValue>
	{
//		/** 用于图片缓存，提升列表中用户头像展现的性能和内存的占用等 */
//		private AsyncBitmapLoader asyncLoader = null;

		public FriendsReqListAdapter(Activity context)
		{
			super(context, R.layout.sns_friends_req_list_item);
//			this.asyncLoader = new AsyncBitmapLoader(AvatarHelper.getUserAvatarSavedDirHasSlash(context));
		}

		@Override
		public View getView(final int position, View convertView, ViewGroup parent)
		{
			//列表item上的：
			TextView viewTitle = null;
			//列表item上的：
			TextView viewMsgContent = null;
			TextView viewDate = null;
			ImageView viewAvatar = null;

			ImageView viewArrowIcon = null;
			Button btnAgree = null;

			//------------------------------------------------------ 【1】UI初始化
			//当的item布局实例已经存在（不在存，意味着这个item刚好从不可见区移到可见区时）
			//** 根据android的列表ui实现，为了节比资源占用，假如列表有100行而可见区显示5行，那么任何时候
			//** 这个列表中只会有5个item的UI存在，其它的item都是当被转到可见区时自动把自
			//** 已的数据实时地更新列UI上，以便查看，也就是说item的UI并不是与后台数据一
			//** 一对应的，所以正如API文档里说的，convertView并不能确保它总能按你的想法保持不为null
			boolean needCreateItem = (convertView == null);
			//正在操作的列表行的数据集
			final FriendsReqItemValue rowData = listData.get(position);
			if (needCreateItem)
				//明细item的UI实例化
				convertView = layoutInflater.inflate(itemResId, null);
			//item里的操作组件实例
			viewTitle = convertView.findViewById(R.id.main_verification_reminders_list_item_titleView);
			viewMsgContent = convertView.findViewById(R.id.main_verification_reminders_list_item_msgView);
			viewDate = convertView.findViewById(R.id.main_verification_reminders_list_item_dateView);
			viewAvatar = convertView.findViewById(R.id.main_verification_reminders_list_item_iconView);
			viewArrowIcon = convertView.findViewById(R.id.multi_chatting_list_view_arrowIco);
			btnAgree = convertView.findViewById(R.id.multi_chatting_list_view_agreeBtn);

			//------------------------------------------------------ 【2】增加事件处理器
			//各操作组件的事件监听器只需要在convertView被实例化时才需要重建（convertView需要被实例化
			//当然就意味着它上面的所有操作组件都已经重新新建了）
			//** 关于事件处理器的说明：事件处理器的增加其实可以不这么麻烦，直接每getView一次就给组件new一个处理器，
			//** 这样做的好处是简单，但显然存在资源浪费（每刷新一次view就新建监听器）。而现在的实现就跟Android的列表
			//** 实现原理一样，在切换到下一组item前，监听器永远只有一屏item的数量（刷新时只需要即时刷新对应item的数据到
			//** 它的监听器里），这样就节省了资源开销！
			if(needCreateItem)
			{
				//
			}
			
			//------------------------------------------------------ 【3】UI值设置
			//给标签设置值，以供用户查看
			viewTitle.setText(rowData.getUserInfo().getNickname());
			viewMsgContent.setText(rowData.getContent());
			viewDate.setText(rowData.getDateHuman());
			if(rowData.isUnread()){
				btnAgree.setVisibility(View.VISIBLE);
				viewArrowIcon.setVisibility(View.GONE);
				viewDate.setVisibility(View.GONE);
			}
			else{
				btnAgree.setVisibility(View.GONE);
				viewArrowIcon.setVisibility(View.VISIBLE);
				viewDate.setVisibility(View.VISIBLE);
			}

			// 根据Glide官方指南的说明：https://muyangmin.github.io/glide-docs-cn/doc/getting-started.html#%E5%9C%A8-listview-%E5%92%8C-recyclerview-%E4%B8%AD%E7%9A%84%E4%BD%BF%E7%94%A8
			// 由于RecycleView中view的复用问题，为了防止图片显示错乱，如果它在之前的位置上用 Glide 进行过加载操作，那么在新的位置上要去执行一个新的加载操作或调用 clear()，
			// 实测通过clear()或通过Glide.with(context).load(默认占位图的资源id)两种方式都可以解决错乱问题，但clear更好，因为它不会在发生图片显示时闪烁一下的问题
//      	Glide.with(context).load(R.drawable.main_alarms_sns_addfriendreject2r_message_icon).into(holder.viewIcon); // 解决方法1
			Glide.with(context).clear(viewAvatar);// 解决方法2
			// clear完成后设置默认占位图，确保图片显示不出现Glide导致的错位问题
			viewAvatar.setImageResource(R.drawable.default_avatar_yuan_50_3x);

			String uidForAvatar = null;
			String fileNameForAvatar = null;
			if (rowData.getUserInfo() != null) {
				//** 再来看看此人有无设置过头像
				// 此字段中存放的是用户对应的头像文件名，为空即表示没有设置头像，否则表示此人设置过头像
				fileNameForAvatar = rowData.getUserInfo().getUserAvatarFileName();
				uidForAvatar = rowData.getUserInfo().getUser_uid();
			}

			//------------------------------------------------------【4】 按需载入用户头像
			if(!CommonUtils.isStringEmpty(fileNameForAvatar)) {
				// 加载头像图片
				ImageCacheLoader.loadAvatarImgWithGlide(context, uidForAvatar, fileNameForAvatar
						, viewAvatar
						, 25 // 圆角单位是dp
						, R.drawable.default_avatar_yuan_50_3x, false, false);
			}

			return convertView;
		}
		
		@Override
		public void notifyDataSetChanged()
		{
			super.notifyDataSetChanged();
			if(this.getCount() <= 0) {
				llNoAlarms.setVisibility(View.VISIBLE);
				listView.setVisibility(View.GONE);
			}
			else {
				llNoAlarms.setVisibility(View.GONE);
				listView.setVisibility(View.VISIBLE);
			}
		}
	}
}
